package com.cdp.web.controller.system;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.cdp.common.constant.CacheConstants;
import com.cdp.common.core.domain.AjaxResult;
import com.cdp.common.core.domain.entity.ChartFiles;
import com.cdp.common.core.domain.entity.ChartRecord;
import com.cdp.common.core.redis.RedisCache;
import com.cdp.common.utils.SecurityUtils;
import com.cdp.common.utils.StringUtils;
import com.cdp.system.dto.ChartFilesDTO;
import com.cdp.system.dto.ChartFolderTreeDTO;
import com.cdp.system.service.IChartConfigsUserService;
import com.cdp.system.service.IChartFilesService;
import com.cdp.system.service.IChartRecordService;
import com.cdp.system.service.ISysUserService;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 我的生成
 */
@Slf4j
@RestController
@RequestMapping()
public class ChartFilesController {


    @Autowired
    private IChartFilesService chartFilesService;
    @Autowired
    private RedisCache redisCache;

    @Autowired
    private IChartRecordService chartRecordService;
    @Autowired
    private IChartConfigsUserService chartConfigsUserService;


    @Autowired
    private ISysUserService sysUserService;





    /**
     * 获取文件夹列表
     *
     * @param request
     * @return
     */
    @GetMapping("/folder/user/list")
    public HashMap<String, Object> getChartFileTreechartList(HttpServletRequest request) {
        // 获取查询参数，如果不存在则为 null
        String name = request.getParameter("name");
        if (StringUtils.isEmpty(name)) {
            name = null;  // name 不传时设置为 null
        }

        // 获取当前用户的 ID
        Long userId = SecurityUtils.getUserId();

        // 参数校验，确保 userId 不为空且大于 0
        if (userId == null || userId <= 0) {
            log.warn("用户ID无效: {}", userId);  // 记录日志
            throw new IllegalArgumentException("无效的用户ID。");  // 抛出参数异常
        }

        // 调用服务层方法获取文件夹树
        List<ChartFolderTreeDTO> folderFileTree = chartFilesService.getUpdatedFolderFileTree(name);
        // 如果文件夹树为空，抛出异常
        if (folderFileTree == null || folderFileTree.isEmpty()) {
            log.warn("用户userId={} 我的生成数据库查询异常", userId);
            throw new IllegalArgumentException("我的生成数据库查询异常。");
        }
        // 查询图表记录
        LambdaQueryWrapper<ChartRecord> lqw = new LambdaQueryWrapper<>();
        lqw.eq(ChartRecord::getUserId, userId);
        lqw.eq(ChartRecord::getDeleteTime, 0);

        List<ChartRecord> chartConfigsUsers = chartRecordService.list(lqw);

        // 获取图表记录数量
        int size = chartConfigsUsers.size();

        // 构建返回数据
        HashMap<String, Object> map = new HashMap<>();
        map.put("msg", "操作成功");
        map.put("code", 200);
        map.put("data", folderFileTree);
        map.put("total", size);
        return map;
    }


    /**
     * 新增文件夹
     *
     * @param chartFilesDTO
     * @return
     */
    @ApiOperation("文件夹：新增")
    @PostMapping("/user/addFolder")
    @Transactional
    public AjaxResult folder(@RequestBody ChartFilesDTO chartFilesDTO) {
        // 判断文件夹名称是否为空
        if (ObjectUtils.isEmpty(chartFilesDTO.getFolderName())) {
            log.warn("文件夹名称为空，请填写文件夹名称");
            return AjaxResult.error("名称为空，请填写文件夹名称");
        }

        // 检查是否存在重复文件夹名称
        ChartFiles existingFolder;
        if (chartFilesDTO.getParentId() == null) {
            // 如果没有父文件夹，查询根目录文件夹是否重复
            existingFolder = chartFilesService.getOne(new LambdaQueryWrapper<ChartFiles>()
                    .isNull(ChartFiles::getParentId)
                    .eq(ChartFiles::getUserId, SecurityUtils.getUserId())
                    .eq(ChartFiles::getFileName, chartFilesDTO.getFolderName())
                    .eq(ChartFiles::getDeleteTime, "0") // 只查询未删除的文件夹
            );
        } else {
            // 如果有父文件夹，查询子目录是否重复
            existingFolder = chartFilesService.getOne(new LambdaQueryWrapper<ChartFiles>()
                    .eq(ChartFiles::getParentId, chartFilesDTO.getParentId())
                    .eq(ChartFiles::getUserId, SecurityUtils.getUserId())
                    .eq(ChartFiles::getFileName, chartFilesDTO.getFolderName())
                    .eq(ChartFiles::getDeleteTime, "0") // 只查询未删除的文件夹
            );
        }

        if (existingFolder != null) {
            log.error("文件夹名称重复，无法保存");
            return AjaxResult.error(409, "文件夹名称重复");
        }

        // 创建新的文件夹记录
        ChartFiles newChartFile = new ChartFiles();
        newChartFile.setUserId(SecurityUtils.getUserId());
        newChartFile.setFileName(chartFilesDTO.getFolderName());
        newChartFile.setParentId(chartFilesDTO.getParentId());
        newChartFile.setDeleteTime(0);  // 默认未删除
        newChartFile.setCreateTime(Date.from(Instant.now()));  // 设置当前时间为创建时间

        // 保存文件夹
        boolean result = chartFilesService.save(newChartFile);

        // 保存
        if (result) {
            log.info("文件夹信息保存成功");

            // 返回成功并带上新生成的 fileId
            Map<String, Object> data = new HashMap<>();
            data.put("fileId", newChartFile.getFileId()); // 返回生成的 fileId


            return AjaxResult.success("文件夹新增成功", data);
        } else {
            log.error("文件夹信息保存失败");
            return AjaxResult.error("文件夹新增失败，请稍后重试");
        }
    }


    /**
     * 删除文件夹
     */
    @PostMapping("/delFolderByFileId")
    @Transactional
    public AjaxResult delByFileIds(@RequestBody ChartFiles chartFiles) {
        // 获取到这个文件夹所有的下级目录和上一级目录
        List<Long> ids = getIds(chartFiles.getFileId());
        if (!CollectionUtils.isEmpty(ids)) {
            // 更新 chart_files 表的 delete_time 字段
            boolean folderUpdated = chartFilesService.update(new LambdaUpdateWrapper<ChartFiles>()
                    .set(ChartFiles::getDeleteTime, System.currentTimeMillis() / 1000)
                    .in(ChartFiles::getFileId, ids));

            if (folderUpdated) {
                List<Long> fileIds = new ArrayList<>();
                for (Long id : ids) {
                    List<ChartRecord> list = chartRecordService.list(new LambdaQueryWrapper<ChartRecord>()
                            .eq(ChartRecord::getFileId, id)
                            .eq(ChartRecord::getUserId, SecurityUtils.getUserId())
                            .eq(ChartRecord::getDeleteTime, 0)); // 确保未被标记为删除
                    if (!CollectionUtils.isEmpty(list)) {
                        fileIds.add(id);
                    }
                }

                if (!CollectionUtils.isEmpty(fileIds)) {
                    // 更新 chart_record 表的 delete_time 字段
                    boolean recordsUpdated = chartRecordService.update(new LambdaUpdateWrapper<ChartRecord>()
                            .set(ChartRecord::getDeleteTime, System.currentTimeMillis() / 1000)
                            .in(ChartRecord::getFileId, fileIds));
                    if (recordsUpdated) {
                        // 仅删除 chart_files 和 chart_record 数据，跳过对 ChartViewsUser 的处理
                        clearCacheAfterFileDelete();  // 清除缓存
                        return AjaxResult.success();
                    }
                } else {
                    // 如果没有相关的 ChartRecord，直接清除缓存
                    clearCacheAfterFileDelete();  // 清除缓存
                    return AjaxResult.success();
                }
            }
        }
        return AjaxResult.error(581, "删除失败");
    }


    /**
     * 清除删除文件夹后的缓存
     */
    private void clearCacheAfterFileDelete() {
        Long userId = SecurityUtils.getUserId();  // 获取当前用户ID
        String cacheKeyPrefix = CacheConstants.CHART_USER_RECORD_KEY + userId;  // 构造缓存Key前缀

        // 获取所有与文件夹相关的缓存键
        Set<String> cacheKeys = new HashSet<>(redisCache.keys(cacheKeyPrefix + "*"));

        // 删除相关缓存
        if (cacheKeys != null && !cacheKeys.isEmpty()) {
            for (String cacheKey : cacheKeys) {
                redisCache.deleteObject(cacheKey);  // 删除缓存
                log.info("删除缓存数据: {}", cacheKey);
            }
        }
    }

    private List<Long> getIds(Long id) {
        Long userId = SecurityUtils.getUserId();
        List<ChartFiles> list = chartFilesService.list(new LambdaQueryWrapper<ChartFiles>().eq(ChartFiles::getUserId, userId));

        Map<Long, ChartFiles> map = list.stream().collect(Collectors.toMap(ChartFiles::getFileId, ChartFiles -> ChartFiles));
        ArrayList<Long> ids = new ArrayList<>();
        map.forEach((key, value) -> {
            Optional.ofNullable(value.getParentId())
                    .map(map::get)
                    .ifPresent(pFile -> {
                        List<ChartFiles> children = pFile.getChildren();
                        if (children == null) {
                            pFile.setChildren(Stream.of(value).collect(Collectors.toList()));
                        } else {
                            children.add(value);
                        }
                    });
        });

        processChartFiles(map, id, ids);
        return ids;
    }

    private void processChartFiles(Map<Long, ChartFiles> map, Long id, List<Long> ids) {
        ChartFiles chartFiles1 = map.get(id);
        if (chartFiles1 == null) {
            return;
        }

        ids.add(chartFiles1.getFileId());

        if (chartFiles1.getChildren() != null) {
            chartFiles1.getChildren().forEach(child -> processChartFiles(map, child.getFileId(), ids));
        }
    }

    /**
     * 删除文件
     */
    @PostMapping("/delFileByFileId")
    public AjaxResult delfile(@RequestBody ChartFiles chartFiles) {

        Long fileId = chartFiles.getFileId();
        LambdaUpdateWrapper<ChartRecord> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(ChartRecord::getDeleteTime, System.currentTimeMillis() / 1000);
        wrapper.in(ChartRecord::getFileId, fileId);
        chartRecordService.update(wrapper);
        return AjaxResult.success();
    }


    /**
     * 根据id查询工作表
     */

    @GetMapping("/queryRecordById")
    public AjaxResult queryRecordById(@RequestParam Long id) {
        // 返回查询结果
        return AjaxResult.success(chartRecordService.queryRecordById(id));
    }


    /**
     * 打散文件夹
     */

    @ApiOperation("文件夹：打散文件")
    @PostMapping("/file/chart/user/break")
    @Transactional
    public AjaxResult scatterBbreak(@RequestBody ChartFiles chartFiles) {
        // 获取目标文件夹的 fileId
        Long fileId = chartFiles.getFileId();

        // 获取当前用户 ID（限制为当前用户）
        Long userId = SecurityUtils.getUserId();
        // 获取目标文件夹及其所有子文件夹的 fileId 列表
        List<Long> folderIds = getFolderIds(fileId, userId);
        if (CollectionUtils.isEmpty(folderIds)) {
            return AjaxResult.error(400, "未找到该文件夹或子文件夹");
        }
        // 更新 chart_record 表，设置这些文件夹中的文件的 file_id 为 NULL
        boolean updated = chartRecordService.update(
                new LambdaUpdateWrapper<ChartRecord>()
                        .set(ChartRecord::getFileId, null) // 将 file_id 设置为 NULL
                        .in(ChartRecord::getFileId, folderIds) // 限定文件夹 ID
        );

        if (!updated) {
            return AjaxResult.error(400, "文件夹内没有找到相关文件，无法打散");
        }

        clearCacheAfterscatterBbreak();
        return AjaxResult.success("文件夹打散成功");
    }


    /**
     * 获取指定文件夹及其所有子文件夹的 fileId 列表
     *
     * @param rootFileId 根文件夹的 fileId
     * @param userId     当前用户的 ID
     * @return 所有相关文件夹的 fileId 列表
     */
    private List<Long> getFolderIds(Long rootFileId, Long userId) {
        // 获取当前用户的所有文件夹
        List<ChartFiles> allFolders = chartFilesService.list(
                new LambdaQueryWrapper<ChartFiles>().eq(ChartFiles::getUserId, userId)
        );

        // 将文件夹列表转换为 Map，方便通过 parentId 构建层级
        Map<Long, ChartFiles> folderMap = allFolders.stream()
                .collect(Collectors.toMap(ChartFiles::getFileId, folder -> folder));

        // 递归收集文件夹 ID
        List<Long> result = new ArrayList<>();
        collectFolderIds(folderMap, rootFileId, result);

        return result;
    }

    /**
     * 递归收集指定文件夹及其所有子文件夹的 ID
     *
     * @param folderMap 所有文件夹的 Map，key 为 fileId
     * @param fileId    当前文件夹的 fileId
     * @param result    收集的文件夹 ID 列表
     */
    private void collectFolderIds(Map<Long, ChartFiles> folderMap, Long fileId, List<Long> result) {
        result.add(fileId); // 添加当前文件夹 ID
        for (ChartFiles folder : folderMap.values()) {
            if (fileId.equals(folder.getParentId())) { // 找到子文件夹
                collectFolderIds(folderMap, folder.getFileId(), result); // 递归处理子文件夹
            }
        }
    }


    /**
     * 清除删除文件夹后的缓存
     */
    private void clearCacheAfterscatterBbreak() {
        Long userId = SecurityUtils.getUserId(); // 获取当前用户ID
        String cacheKeyPrefix = CacheConstants.CHART_USER_RECORD_KEY + userId; // 构造缓存Key前缀

        // 获取所有与文件夹相关的缓存键
        Set<String> cacheKeys = new HashSet<>(redisCache.keys(cacheKeyPrefix + "*"));

        // 删除相关缓存
        if (cacheKeys != null && !cacheKeys.isEmpty()) {
            for (String cacheKey : cacheKeys) {
                redisCache.deleteObject(cacheKey); // 删除缓存
                log.info("删除缓存数据: {}", cacheKey);
            }
        }
    }


}
